﻿using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Action = Styx.TreeSharp.Action;


namespace HunterMM
{
    public partial class Main : CombatRoutine
    {
        public override string Name { get { return "MM Hunter Quick and Dirty by Pasterke"; } }
        public override WoWClass Class { get { return WoWClass.Hunter; } }
        public LocalPlayer Me { get { return StyxWoW.Me; } }


        private Composite _combat, _buffs;

        public string LastSpell = string.Empty;
        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }
        public bool isBoss { get { return IsWoWBoss(StyxWoW.Me.CurrentTarget); } }
        public string DireCrows { get { return callBeast(); } }
        public bool Solo { get { return SoloOrNot(); } }

        public override bool WantButton { get { return true; } }

        public override void OnButtonPress()
        {
            Form1 ConfigForm = new Form1();
            ConfigForm.ShowDialog();
        }


        public override void Initialize()
        {
            Lua.Events.AttachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
            Updater.CheckForUpdate(UpdateSettingsHunterMM.myPrefs.Revision);
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }

        public override void ShutDown()
        {
            Lua.Events.DetachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
        }

        Composite CreateBuffs()
        {
            return new PrioritySelector(ret => !Paused && !buffExists(FEIGN_DEATH, Me),
                            Cast("Mend Pet", ret => !Me.Combat && StyxWoW.Me.GotAlivePet
                            && StyxWoW.Me.Pet.HealthPercent <= CRSettingsMM.myPrefs.useMendPet && !StyxWoW.Me.Pet.HasAura("Mend Pet")),
                            Cast("Aspect of the Hawk", ret => !StyxWoW.Me.HasAura("Aspect of the Hawk") && !SpellManager.HasSpell("Aspect of the Iron Hawk")),
                            Cast("Aspect of the Iron Hawk", ret => !StyxWoW.Me.HasAura("Aspect of the Iron Hawk")),
                            Cast("Trap Launcher", ret => !StyxWoW.Me.HasAura("Trap Launcher")),
                            new Decorator(ret => StyxWoW.Me.HealthPercent <= CRSettingsMM.myPrefs.useHealthstone, new Action(ret => { Healthstone(); return RunStatus.Failure; }))
                );
        }


        Composite CreateCombat()
        {

            return new PrioritySelector(ret => !Paused && !buffExists(FEIGN_DEATH, Me) && Me.CurrentTarget != null,
                new Decorator(ret => buffExists(FIRE, Me), new PrioritySelector(Cast("Aimed Shot"))),
                new Decorator(ret => UnfriendlyUnits.Count() >= CRSettingsMM.myPrefs.StartAoe && !PauseAoe, CreateAoe()),
                new Decorator(ret => !debuffExists("Serpent Sting", Me.CurrentTarget) && Me.FocusPercent >= 15 && LastSpell != "Serpent Sting", SerpentRotation()),
                new Decorator(ret => !Me.CurrentTarget.Name.Contains("Dummy") && Me.CurrentTarget.HealthPercent >= 80, AimedRotation()),
                new Decorator(ret => (!buffExists(STEADY_FOCUS, Me)
                    || (buffExists(STEADY_FOCUS, Me)
                    && buffTimeLeft(STEADY_FOCUS, Me) <= 4000) && Me.CurrentTarget.HealthPercent < 80), SteadyRotation()),
                new Decorator(ret => (Me.CurrentTarget.HealthPercent < 80 || Me.CurrentTarget.Name.Contains("Dummy"))
                    && (UnfriendlyUnits.Count() < CRSettingsMM.myPrefs.StartAoe || PauseAoe), MMRotation())
                );
        }
        Composite SteadyRotation()
        {
            return new PrioritySelector(
                Cast("Steady Shot")
                );
        }
        Composite SerpentRotation()
        {
            return new PrioritySelector(
                Cast("Serpent Sting")
                );
        }
        Composite AimedRotation()
        {
            return new PrioritySelector(
                Cast("Silencing Shot", ret => !spellOnCooldown("Silencing Shot") && Me.CurrentTarget.IsCasting && Me.CanInterruptCurrentSpellCast),
                Cast("Revive Pet", ret => Me.Pet != null && Me.Pet.IsDead),
                Cast("Mend Pet", ret => Me.GotAlivePet
                      && Me.Pet.HealthPercent <= CRSettingsMM.myPrefs.useMendPet
                      && !buffExists("Mend Pet", Me.Pet)
                      && LastSpell != "Mend Pet"),
                Cast("Rapid Fire", ret => isBoss && !spellOnCooldown("Rapid Fire") && LastSpell != "Rapid Fire"),
                Cast("Stampede", ret => isBoss && !spellOnCooldown("Stampede") && LastSpell != "Stampede"),
                Cast("Dire Beast", ret => CRSettingsMM.myPrefs.useDireBeast && !spellOnCooldown("Dire Beast") && LastSpell != "Dire Beast"),
                Cast("Lifeblood", ret => CRSettingsMM.myPrefs.useLifeblood && isBoss && !spellOnCooldown("Lifeblood") && LastSpell != "Lifeblood"),
                Cast("Blood Fury", ret => CRSettingsMM.myPrefs.useBloodFury && isBoss && !spellOnCooldown("Blood Fury") && LastSpell != "Blood Fury"),
                Cast("Berserking", ret => CRSettingsMM.myPrefs.useBerserking && isBoss && !spellOnCooldown("Berserking") && LastSpell != "Berserking"),
                new Decorator(ret => isBoss, new Action(ret => { UseTrinkets(); return RunStatus.Failure; })),
                new Decorator(ret => CRSettingsMM.myPrefs.useVirmenPotions && !Me.CurrentTarget.Name.Contains("Dummy") && isBoss,
                    new Action(ret => { VirmenPotion(); return RunStatus.Failure; })),
                Cast("Aimed Shot", ret => Me.FocusPercent >= 50),
                Cast("Steady Shot", ret => Me.FocusPercent < 50)
                );
        }
        Composite MMRotation()
        {
            return new PrioritySelector(ret => StyxWoW.Me.CurrentTarget != null,
                        Cast("Silencing Shot", ret => !spellOnCooldown("Silencing Shot")
                            && Me.CurrentTarget.IsCasting
                            && Me.CanInterruptCurrentSpellCast
                            && LastSpell != "Silencing Shot"),
                        Cast("Revive Pet", ret => Me.Pet != null && Me.Pet.IsDead),
                        Cast("Mend Pet", ret => Me.GotAlivePet
                            && Me.Pet.HealthPercent <= CRSettingsMM.myPrefs.useMendPet
                            && !buffExists("Mend Pet", Me.Pet)),
                        Cast("Concussive Shot", ret => Me.MovementInfo.MovingBackward && !debuffExists("Concussive Shot", Me.CurrentTarget) && LastSpell != "Concussive Shot"),
                        DropCastOnMe("Ice Trap", ret => StyxWoW.Me.MovementInfo.MovingBackward && buffExists("Trap Launcher", Me) && !spellOnCooldown("Ice Trap")),
                        Cast("Kill Shot", ret => Me.CurrentTarget.HealthPercent <= 20 && !spellOnCooldown("Kill Shot")),
                        Cast("Stampede", ret => isBoss && !spellOnCooldown("Stampede")),
                        Cast("A Murder of Crows", ret => isBoss && !spellOnCooldown("A Murder of Crows") && Me.FocusPercent >= 60),
                        Cast("Rapid Fire", ret => isBoss && !spellOnCooldown("Rapid Fire") && LastSpell != "Rapid Fire"),
                        Cast("Lifeblood", ret => CRSettingsMM.myPrefs.useLifeblood && isBoss && !spellOnCooldown("Lifeblood")),
                        Cast("Blood Fury", ret => CRSettingsMM.myPrefs.useBloodFury && isBoss && !spellOnCooldown("Blood Fury")),
                        Cast("Berserking", ret => CRSettingsMM.myPrefs.useBerserking && isBoss && !spellOnCooldown("Berserking")),
                        new Decorator(ret => isBoss, new Action(ret => { UseTrinkets(); return RunStatus.Failure; })),
                        new Decorator(ret => CRSettingsMM.myPrefs.useVirmenPotions && !Me.CurrentTarget.Name.Contains("Dummy") && isBoss, new Action(ret => { VirmenPotion(); return RunStatus.Failure; })),
                        Cast("Dire Beast", ret => CRSettingsMM.myPrefs.useDireBeast && !spellOnCooldown("Dire Beast")),

                        DropCast("Explosive Trap", ret => useExplosiveTrap() && buffExists("Trap Launcher", Me) && !spellOnCooldown("Explosive Trap")),
                        Cast("Chimera Shot", ret => !spellOnCooldown("Chimera Shot") && Me.FocusPercent >= 45),
                        Cast("Glaive Toss", ret => Me.FocusPercent >= 15 && !spellOnCooldown("Glaive Toss")),
                        Cast("Arcane Shot", ret => Me.FocusPercent > CRSettingsMM.myPrefs.useArcaneFocus),
                        Cast("Steady Shot", ret => Me.FocusPercent <= 45)
                    );
        }
        Composite CreateAoe()
        {
            return new PrioritySelector(ret => StyxWoW.Me.CurrentTarget != null,
                            Cast("Revive Pet", ret => StyxWoW.Me.Pet != null && StyxWoW.Me.Pet.IsDead),
                            Cast("Mend Pet", ret => Me.GotAlivePet && Me.Pet.HealthPercent <= CRSettingsMM.myPrefs.useMendPet && !buffExists("Mend Pet", Me.Pet)),
                            DropCast("Explosive Trap", ret => buffExists("Trap Launcher", Me) && !spellOnCooldown("Explosive Trap")),
                            Cast("Multi-Shot"),
                            Cast("Steady Shot", ret => StyxWoW.Me.FocusPercent < 40)
                );
        }
        public int STEADY_FOCUS = 53220;
        public int FIRE = 82926;
        public int FEIGN_DEATH = 5384;

        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if (firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if (secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }
        void VirmenPotion()
        {
            var virmen = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 76089);
            if (virmen != null && virmen.Usable && virmen.Cooldown <= 0)
            {
                virmen.Use();
            }
        }
        void Healthstone()
        {
            var hstone = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 5512);
            if (hstone != null && hstone.Usable && hstone.Cooldown <= 0)
            {
                hstone.Use();
            }
        }

        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
            {
                return false;
            }


            return item.Usable && item.Cooldown <= 0;
        }


        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead
                    && u.CanSelect
                    && u.Attackable
                    && !u.IsFriendly
                    && !u.Name.Contains("Dummy")
                    && u.Location.Distance(StyxWoW.Me.CurrentTarget.Location) <= 10);
            }
        }


        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        Logging.Write(spell);
                        LastSpell = spell;
                    }
                        ));
        }
        Composite DropCast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        StyxWoW.SleepForLagDuration();
                        SpellManager.ClickRemoteLocation(StyxWoW.Me.CurrentTarget.Location);
                        Logging.Write(spell);
                        LastSpell = spell;
                    }));
        }
        Composite DropCastOnMe(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        StyxWoW.SleepForLagDuration();
                        SpellManager.ClickRemoteLocation(StyxWoW.Me.Location);
                        Logging.Write(spell);
                        LastSpell = spell;
                    }));
        }

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }


        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {
            if (StyxWoW.Me.CurrentTarget != null)
            {
                if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
                {
                    return true;
                }
                else if (target.IsBoss(mytarget))
                {
                    return true;
                }
                else if (Me.CurrentTarget.MaxHealth >= (100 * 1000000)) { return true; }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 3)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.Name.Contains("Dummy")
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.IsPlayer
                    && !StyxWoW.Me.CurrentTarget.IsFriendly)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion Kind of Target

        #region callbeast
        public string callBeast()
        {
            string whatBeast = CRSettingsMM.myPrefs.tier5.ToString();
            switch (whatBeast)
            {
                case "None":
                    return string.Empty;
                case "A_Murder_of_Crows":
                    return "A Murder of Crows";
                case "LynxRush":
                    return "Lynx Rush";
                default:
                    return string.Empty;
            }
        }
        #endregion

        #region pause
        public static bool PauseAoe = false;
        public static bool Paused = false;

        public static void HandleModifierStateChanged(object sender, LuaEventArgs args)
        {
            if (CRSettingsMM.myPrefs.StopCRKey == CRSettingsMM.Keypress.NONE
                && CRSettingsMM.myPrefs.StopAoeKey == CRSettingsMM.Keypress.NONE)
            {
                return;
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                string pauseMyAoe = "AOE cancelled, press " + CRSettingsMM.myPrefs.StopAoeKey.ToString() + " in WOW again to turn AOE back on";
                if (args.Args[0].ToString() == CRSettingsMM.myPrefs.StopAoeKey.ToString())
                {
                    PauseAoe = !PauseAoe;
                    if (PauseAoe)
                    {
                        Logging.Write("Aoe cancelled, press {0} in WOW again to resume Aoe",
                                     CRSettingsMM.myPrefs.StopAoeKey.ToString());
                        if (CRSettingsMM.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseMyAoe + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Aoe Resumed");
                        if (CRSettingsMM.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Aoe Resumed !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == CRSettingsMM.myPrefs.StopCRKey.ToString())
                {
                    string pauseCR = "CR paused, press " + CRSettingsMM.myPrefs.StopCRKey.ToString() + " in WOW again to turn back on";
                    Paused = !Paused;
                    if (Paused)
                    {
                        Logging.Write("CR paused, press {0} in WOW again to turn back on",
                                     CRSettingsMM.myPrefs.StopCRKey.ToString());
                        if (CRSettingsMM.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseCR + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("CR running again ....");
                        if (CRSettingsMM.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"CR running again ....\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
        }
        #endregion pause

        #region solo or not
        public bool SoloOrNot()
        {
            return (!StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                && !StyxWoW.Me.GroupInfo.IsInRaid
                && !StyxWoW.Me.IsInInstance;
        }
        #endregion

        #region explotrap
        public bool useExplosiveTrap()
        {
            string trap = CRSettingsMM.myPrefs.useExploTrap.ToString();
            switch (trap)
            {
                case "Never":
                    return false;
                case "Always":
                    return true;
                case "BossOnly":
                    if (isBoss) { return true; }
                    return false;
                default:
                    return false;
            }
        }
        #endregion
    }
}
